package org.smartboot.compare;

import org.smartboot.compare.builtin.InnerThisFieldFilter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Field filters.
 *
 * @author qinluo
 * @date 2022-03-10 17:48:00
 * @since 1.0.0
 */
public class FieldFilters implements FieldFilter {

    /**
     * registered filters.
     */
    private final List<FieldFilter> registered = new ArrayList<>(8);

    /**
     * Single instance for global.
     */
    private static final FieldFilters INSTANCE = new FieldFilters();

    static {
        registerGlobal(new InnerThisFieldFilter());
    }

    /**
     * Register global filter.
     *
     * @param filter unregistered filter.
     */
    public static void registerGlobal(FieldFilter filter) {
        if (filter != null) {
            INSTANCE.remove(filter);
            INSTANCE.register(filter);
        }
    }

    /**
     * Remove global filter.
     *
     * @param filter registered filter.
     */
    public static void removeGlobal(FieldFilter filter) {
        if (filter != null) {
            INSTANCE.remove(filter);
        }
    }

    /**
     * Return global registered filters.
     *
     * @return global registered filters
     */
    static List<FieldFilter> globalRegisteredFilters() {
        return Collections.unmodifiableList(INSTANCE.registered);
    }

    /**
     * Remove registered filter.
     *
     * @param filter registered filter.
     */
    public void remove(FieldFilter filter) {
        if (filter != null) {
            registered.remove(filter);
        }
    }

    /**
     * Register filter, will ignore duplicated filter.
     *
     * @param filter unregistered filter.
     */
    public void register(FieldFilter filter) {
        if (filter != null) {
            registered.remove(filter);
            registered.add(filter);
        }
    }


    @Override
    public boolean filtered(FieldCache f, ComparatorContext<?> context, Path curPath) {
        List<FieldFilter> executedFilters = new ArrayList<>(16);
        executedFilters.addAll(globalRegisteredFilters());
        executedFilters.addAll(registered);

        for (FieldFilter filter : executedFilters) {
            if (filter.filtered(f, context, curPath)) {
                return true;
            }
        }
        return false;

    }
}
